不同的语言之间通常可以互相调用,一个工程使用不同的语言来编写也是经常有的情况。
运行时(runtime),就是代码运行的环境,一个语言可能会使用FFI
(Foreign Function Interface)来与其他语言进行通讯,与其他情况不一样的是,Swift是包含OC的运行时的,所以Swift与OC之间的混编会方便很多。
Objective-C中调用Swift
建立一个mac的工程,如下所示:
在这个位置新建一个Swift文件,这是系统会提示询问是否要要自动创建bridging header,这个文件是swift调用oc的代码时需要用到的,为了演示,我们选择不自动创建,后面再手动创建:
现在目录如下所示:
编写swift代码:
import Foundation
public class SwiftCode: NSObject {
@objc public func testSwiftCode() {
print("testSwiftCode")
}
}
这里需要注意的是:
- 定义类必须是public class
- 类要继承NSObject
- 定义的方法必须是带
@objc
前缀的 - 方法必须是public的
我们可以查看swift Interface文件来看我们的swift文件对外暴露了哪些方法和类,这个文件的并不真实存在,作用类似与c和oc的.h文件,swift中只是为了我们方便看。
要想让OC能调用Swift的代码,需要在OC中导入一个xxx-Swift.h文件,这个文件系统已经帮我们自动生成了,查看这个文件的方法如下:
在这个文件的最下面,我们可以看到:
我们编写OC代码:
#import "AppDelegate.h"
#import "OC_Swift_Interoperability-Swift.h"
@interface AppDelegate ()
@property (strong) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
SwiftCode *swiftcode = [[SwiftCode alloc] init];
[swiftcode testSwiftCode];
}
@end
现在运行程序,就可以看到控制台输出:testSwiftCode
Swift返回结构体给Objective-C
如果一个Swift的方法返回类型为结构体,这个方法是不能在前面加@objc
的,Swift的结构体不能直接返回给OC,这个时候我们可以新建一个Swift类,这个类相当于对要使用的结构体包一层,各个方法返回结构体对应的成员,具体做法可以见:How to use Swift struct in Objective-C
Swift中调用Objective-C
Bridging Header的方式
建立一个oc的类用于测试,如下:
建立一个头文件,名字为xxx-Bridging-Header.h这个头文件的内容就是import你想要在Swift中使用的Objective-C类,这里的情况,头文件名字为OC-Swift-Interoperability-Bridging-Header.h,内容如下:
在Build Settings中,在Swift Compiler - General中,设置Objective-C Bridging Header为刚刚建立的头文件
注意这里为头文件在项目中的绝对地址(跟info.pllist的设置一样),如项目文件夹为aaa,头文件在项目根目录,那么就设置为aaa/xxx-Bridging-Header.h。这里的情况如下:
设置好后build一下就可以直接在Swift中使用Objective-C的类了,修改SwiftCode.swift的代码,以及运行结果如下:
.modulemap的方式
modules 是一种更好用的代码库形式,原本的 #include 来导入一个库有一些不足的地方,modules 更好的解决了一些问题,关于modules的详细说明可以看看llvm关于modules的官方文档
具体的modulemap的方式实现swift调用oc代码,可以看这篇文章就好,已经很简洁明了。
参考
Swift and Objective-C in the Same Project